﻿using System;
using System.Collections.Generic;

namespace ASPItalia.ModelVirtualCasting.Random
{
    public sealed class RandomNumberGenerator : IRandomNumberGenerator
    {
        private const int MIN_LENGTH = 1;
        private const int MAX_LENGTH = 16384;

        private static volatile RandomNumberGenerator _instance = null;
        private static object _sync = new object();

        private readonly IRandomNumberGenerator _generator = null;

        public static RandomNumberGenerator Instance
        {
            get
            {
                if (_instance.IsNull())
                {
                    lock (_sync)
                    {
                        if (_instance.IsNull())
                            _instance = new RandomNumberGenerator();
                    }
                }

                return _instance;
            }
        }

        private RandomNumberGenerator()
        {
            int[] seed = new int[256];
            DateTime now = DateTime.Now;
            int startValue = now.Second * 1000 + now.Millisecond;

            for (int i = 0; i < seed.Length; i++)
                seed[i] = startValue + i;
            
            _generator = new IsaacRandomNumberGenerator(seed);
        }

        public int Generate(int lowerBound, int upperBound)
        {
            int randomNumber = -1;
            lowerBound = Math.Abs(lowerBound);
            upperBound = Math.Abs(upperBound);

            if (lowerBound <= upperBound)
            {
                lock (this)
                {
                    randomNumber = _generator.Generate(lowerBound, upperBound);
                }
            }

            return randomNumber;
        }

        public int[] Generate(int lowerBound, int upperBound, int length)
        {
            if ((length < MIN_LENGTH) || (length > MAX_LENGTH))
                return new int[0];

            lowerBound = Math.Abs(lowerBound);
            upperBound = Math.Abs(upperBound);

            if (lowerBound > upperBound)
                return new int[0];

            int[] randomNumbers = new int[length];

            lock (this)
            {
                randomNumbers = _generator.Generate(lowerBound, upperBound, length);
            }

            return randomNumbers;
        }

        public double Generate()
        {
            double randomValue = (double) -1;

            lock (this)
            {
                randomValue = _generator.Generate();
            }

            return randomValue;
        }

        public double[] Generate(int length)
        {
            if ((length < MIN_LENGTH) || (length > MAX_LENGTH))
                return new double[0];

            double[] randomValues = new double[length];

            lock (this)
            {
                randomValues = _generator.Generate(length);
            }

            return randomValues;
        }
    }
}
